<template>
  <div ref="chartContainer" class="line-chart-container pos-relative"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as d3 from "d3";

const props = defineProps<{
  data: number[];
  tooltip?: boolean;
  showFillBg?: boolean;
  highlightColor?: string;
  showGrid?: boolean;
  gridColor?: string;
  margin?: { top: number; right: number; bottom: number; left: number };
}>();

// 常量定义
const HOVER_RADIUS = 30;
const CHART_HEIGHT = 200;
const MARGIN = { top: 20, right: 10, bottom: 30, left: 30 };
const GRID_LINE_OPACITY = 0.25;
const TOOLTIP_BG_COLOR = "rgba(0,0,0,0.8)";
const AREA_OPACITY = 0.2; // 新增：背景区域透明度

// 类型定义
interface DataPoint {
  date: string;
  value: number;
}

interface DataSeries {
  name: string;
  color: string;
  values: number[];
}

interface ChartData {
  dates: string[];
  series: DataSeries[];
}
const width = ref(0);
const height = ref(0);
const offsetX = ref<number>(0);
const offsetY = ref<number>(0);
// 响应式引用
const chartContainer = ref<HTMLElement>();
const verticalLine = ref<d3.Selection<SVGLineElement, unknown, null, undefined> | null>(
  null
);
const tooltip = ref<d3.Selection<HTMLDivElement, unknown, null, undefined> | null>(null);

// 图表数据
const chartData: ChartData = {
  dates: [
    "2023-01",
    "2023-02",
    "2023-03",
    "2023-04",
    "2023-05",
    "2023-06",
    "2023-07",
    "2023-08",
  ],
  series: [
    {
      name: "数据1",
      color: "#4dabf7",
      values: [30, 80, 45, 60, 75, 50, 65, 70],
    },
    {
      name: "数据2",
      color: "#ff5252",
      values: [45, 60, 75, 50, 65, 70, 30, 80],
    },
    {
      name: "数据3",
      color: "#32cd32",
      values: [20, 45, 30, 55, 40, 60, 35, 50],
    },
  ],
};

// 生命周期钩子
onMounted(() => {
  width.value = chartContainer.value?.clientWidth as number;
  height.value = chartContainer.value?.clientHeight as number;
  offsetX.value = chartContainer.value?.getBoundingClientRect().left as number;
  offsetY.value = chartContainer.value?.getBoundingClientRect().top as number;
  initChart();
  initResizeObserver();
});

onBeforeUnmount(() => {
  resizeObserver?.disconnect();
});

// 响应式调整
let resizeObserver: ResizeObserver;

const initResizeObserver = () => {
  if (!chartContainer.value) return;

  resizeObserver = new ResizeObserver(() => {
    initChart();
  });
  resizeObserver.observe(chartContainer.value);
};

// 主初始化函数
const initChart = () => {
  if (!chartContainer.value) return;

  // 清除旧图表
  d3.select(chartContainer.value).selectAll("*").remove();

  // 创建工具提示
  tooltip.value = createTooltip();

  // 渲染图表
  renderChart();
};

// 创建工具提示
const createTooltip = (): d3.Selection<HTMLDivElement, unknown, null, undefined> => {
  if (!chartContainer.value) throw new Error("Chart container not found");

  return d3
    .select(chartContainer.value)
    .append("div")
    .attr("class", "tooltip")
    .style("opacity", 0)
    .style("position", "absolute")
    .style("background", TOOLTIP_BG_COLOR)
    .style("min-width", "100px")
    .style("color", "white")
    .style("border-radius", "4px")
    .style("padding", "8px 12px")
    .style("pointer-events", "none")
    .style("font-size", "12px")
    .style("box-shadow", "0 2px 8px rgba(0,0,0,0.2)");
};

// 主渲染函数
const renderChart = () => {
  if (!chartContainer.value || !tooltip.value) return;

  const width = chartContainer.value.clientWidth;
  const height = CHART_HEIGHT;
  const chartWidth = width - MARGIN.left - MARGIN.right;
  const chartHeight = height - MARGIN.top - MARGIN.bottom;

  // 创建SVG容器
  const svg = d3
    .select(chartContainer.value)
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("viewBox", `0 0 ${width} ${height}`)
    .style("border", "none")
    .style("outline", "none");

  // 定义绘图区域
  const chart = svg
    .append("g")
    .attr("transform", `translate(${MARGIN.left},${MARGIN.top})`);

  // 计算最大值
  const maxValue = Math.max(...chartData.series.flatMap((series) => series.values));

  // 创建比例尺
  const xScale = d3
    .scaleBand()
    .domain(chartData.dates)
    .range([0, chartWidth])
    .padding(0.2);

  const yScale = d3.scaleLinear().domain([0, maxValue]).range([chartHeight, 10]).nice();

  // 渲染各个部分
  renderAxes(chart, xScale, yScale, chartHeight);
  renderGridLines(chart, xScale, yScale, chartWidth, chartHeight);
  renderDataSeries(chart, xScale, yScale, chartWidth, chartHeight);
  renderInteractions(chart, xScale, yScale, chartWidth, chartHeight);
  renderChartTitle(chart, chartData.series, chartWidth);
};
const renderChartTitle = (chart: any, series: DataSeries[], chartWidth: number) => {
  // 创建标题组
  const titleGroup = chart
    .append("g")
    .attr("class", "chart-titles")
    .attr("transform", `translate(0, -10)`); // 向上偏移，避免与图表重叠

  // 计算每个标题的间距
  const titleSpacing = chartWidth / (series.length + 1);
  // 为每个系列添加标题
  series.forEach((s, i) => {
    const title = titleGroup
      .append("g")
      .attr("class", `series-title series-title-${i}`)
      .attr("transform", `translate(${titleSpacing * (i + 1)}, 0)`)
      .style("cursor", "pointer");

    // 添加颜色标记（小方块）
    title
      .append("rect")
      .attr("x", -10)
      .attr("y", -6)
      .attr("width", 10)
      .attr("height", 10)
      .attr("rx", 2)
      .attr("ry", 2)
      .attr("fill", s.color);

    // 添加文本标签
    title
      .append("text")
      .attr("x", 5)
      .attr("y", 0)
      .attr("dy", "0.35em")
      .text(s.name)
      .style("font-size", "12px")
      .style("fill", "#666")
      .style("font-weight", "bold");

    title.on("mouseover", function (_event: any, _d: any) {
      // 切换对应折线的高亮状态
      const line = chart.select(`.line-${i}`);
      const isHighlighted = line.attr("stroke-width") === "1.5";

      line
        .transition()
        .attr("stroke-width", isHighlighted ? 2.5 : 1.5)
        .attr("opacity", isHighlighted ? 1 : 0.8);
    });
  });
};
// 渲染坐标轴
const renderAxes = (
  chart: d3.Selection<SVGGElement, unknown, null, undefined>,
  xScale: d3.ScaleBand<string>,
  yScale: d3.ScaleLinear<number, number, never>,
  chartHeight: number
) => {
  // X轴
  chart
    .append("g")
    .attr("class", "x-axis")
    .attr("transform", `translate(0,${chartHeight})`)
    .call(d3.axisBottom(xScale))
    .select("path.domain")
    .attr("stroke", "none")
    .remove();

  // Y轴
  chart
    .append("g")
    .attr("class", "y-axis")
    .call(d3.axisLeft(yScale))
    .select("path.domain")
    .remove();
};

// 渲染网格线
const renderGridLines = (
  chart: d3.Selection<SVGGElement, unknown, null, undefined>,
  xScale: d3.ScaleBand<string>,
  yScale: d3.ScaleLinear<number, number, never>,
  chartWidth: number,
  chartHeight: number
) => {
  // 水平网格线
  chart
    .selectAll(".grid-line")
    .data(yScale.ticks())
    .enter()
    .append("line")
    .attr("class", "grid-line")
    .attr("x1", 0)
    .attr("x2", chartWidth)
    .attr("y1", (d) => yScale(d) + 0)
    .attr("y2", (d) => yScale(d) + 0)
    .attr("stroke", "#ccc")
    .attr("stroke-opacity", GRID_LINE_OPACITY)
    .attr("stroke-dasharray", "2,2")
    .attr("shape-rendering", "crispEdges");

  // 垂直网格线
  chart
    .selectAll(".grid-vertical")
    .data(chartData.dates)
    .enter()
    .append("line")
    .attr("class", "grid-vertical")
    .attr("x", (d) => xScale(d)! - HOVER_RADIUS / 2)
    .attr("y", 0)
    .attr("width", xScale.bandwidth() + HOVER_RADIUS)
    .attr("height", chartHeight)
    .attr("stroke", "#eee")
    .attr("stroke-opacity", GRID_LINE_OPACITY)
    .attr("stroke-dasharray", "2,2")
    .attr("shape-rendering", "crispEdges");
};

// 渲染数据系列
const renderDataSeries = (
  chart: d3.Selection<SVGGElement, unknown, null, undefined>,
  xScale: d3.ScaleBand<string>,
  yScale: d3.ScaleLinear<number, number, never>,
  _chartWidth: number,
  chartHeight: number
) => {
  chartData.series.forEach((series, index) => {
    const dataPoints = chartData.dates.map((date, i) => ({
      date,
      value: series.values[i],
    }));
    if (props.showFillBg) {
      // 创建区域生成器（新增）
      const area = d3
        .area<DataPoint>()
        .x((d) => xScale(d.date)! + xScale.bandwidth() / 2)
        .y0(chartHeight - 0) // 底部位置（x轴）
        .y1((d) => yScale(d.value)) // 顶部位置（数据点）
        .curve(d3.curveMonotoneX);

      // 绘制半透明背景区域（新增）
      chart
        .append("path")
        .datum(dataPoints)
        .attr("class", `area area-${index}`)
        .attr("d", area)
        .attr("fill", series.color)
        .attr("fill-opacity", AREA_OPACITY)
        .attr("stroke", "none")
        .attr("transform", `translate(0, 0)`);
    }
    // 创建折线
    const line = d3
      .line<DataPoint>()
      .x((d) => xScale(d.date)! + xScale.bandwidth() / 2)
      .y((d) => yScale(d.value))
      .curve(d3.curveMonotoneX);

    chart
      .append("path")
      .datum(dataPoints)
      .attr("class", `line-path line-${index}`)
      .attr("d", line)
      .attr("fill", "none")
      .attr("stroke", series.color)
      .attr("stroke-width", 1.5)
      .attr("transform", `translate(0, 0)`);

    // 创建数据点
    chart
      .selectAll(`.data-point-${index}`)
      .data(dataPoints)
      .enter()
      .append("circle")
      .attr("class", `data-point data-point-${index}`)
      .attr("cx", (d) => xScale(d.date)! + xScale.bandwidth() / 2)
      .attr("cy", (d) => yScale(d.value) + 0)
      .attr("r", 3)
      .attr("fill", series.color)
      .attr("transform", `translate(0, 0)`);
  });
};

// 渲染交互元素
const renderInteractions = (
  chart: d3.Selection<SVGGElement, unknown, null, undefined>,
  xScale: d3.ScaleBand<string>,
  _yScale: d3.ScaleLinear<number, number, never>,
  chartWidth: number,
  chartHeight: number
) => {
  if (!tooltip.value) return;

  // 创建悬停区域
  // const _hoverArea =  
   chart
    .append("rect")
    .attr("class", "hover-area")
    .attr("x", -xScale.bandwidth() / 2)
    .attr("y", 0)
    .attr("width", chartWidth + xScale.bandwidth())
    .attr("height", chartHeight)
    .attr("opacity", 0)
    .on("mousemove", handleMouseMove)
    .on("mouseleave", handleMouseLeave);

  // 鼠标移动处理
  function handleMouseMove(this: SVGRectElement, event: MouseEvent) {
    const mouseX = d3.pointer(event, this)[0];
    const xDomain = xScale.domain();
    const bandWidth = xScale.bandwidth();
    //  const padding = xScale.paddingInner() * bandWidth;

    // 改进的索引计算方式，考虑边缘情况
    const step = (chartWidth - bandWidth) / (xDomain.length - 1); // 使用点数减1来计算步长
    let index = Math.round((mouseX - bandWidth / 2) / step);
    index = Math.max(0, Math.min(index, xDomain.length - 1));

    const date = xDomain[index];
    const xPos = xScale(date)! + bandWidth / 2;

    // 更新垂直参考线
    updateVerticalLine(xPos, chartHeight);

    // 高亮当前数据点
    highlightCurrentPoint(date, index);

    // 更新工具提示
    updateTooltip(event, date, index);
  }

  // 鼠标离开处理
  function handleMouseLeave() {
    resetChartStyles();
    hideVerticalLine();
    hideTooltip();
  }

  // 更新垂直参考线
  function updateVerticalLine(xPos: number, height: number) {
     // 确保参考线不会超出图表范围
  const minX = xScale.bandwidth() / 2;
  const maxX = chartWidth - xScale.bandwidth() / 2;
    xPos = Math.max(minX, Math.min(xPos, maxX));
    if (!verticalLine.value) {
      verticalLine.value = chart
        .append("line")
        .attr("class", "vertical-line")
        .attr("x1", xPos)
        .attr("x2", xPos)
        .attr("y1", 0)
        .attr("y2", height)
        .attr("stroke", "#666")
        .attr("stroke-width", 1)
        .attr("stroke-dasharray", "3,3")
        .attr("opacity", 0);
    }

    verticalLine.value
      .attr("x1", xPos)
      .attr("x2", xPos)
      .transition()
      .duration(100)
      .attr("opacity", 0.8);
  }

  // 高亮当前数据点
  function highlightCurrentPoint(date: string, index: number) {
    // 高亮垂直网格线
    chart
      .selectAll(".grid-vertical")
      .filter((d) => d === date)
      .transition()
      .duration(200)
      .attr("stroke", "#4dabf7")
      .attr("stroke-opacity", 0.8)
      .attr("stroke-width", 2)
      .attr("opacity", 0.8);

    // 高亮数据点  
    chartData.series.forEach((_series, seriesIndex) => {
      chart
        .selectAll(`.data-point-${seriesIndex}`)
        .filter((_, i) => i === index)
        .attr("r", 6)
        .attr("fill", "#ff5252");
    });
  }

  // 更新工具提示
  function updateTooltip(event: MouseEvent, date: string, index: number) {
    if (!tooltip.value) return;
    // 计算工具提示位置，避免超出屏幕
    const tooltipWidth = 120; // 预估工具提示宽度
    const tooltipHeight = 80;
    let left = event.pageX - offsetX.value+ 15;
    let top = event.pageY- offsetY.value - 28;
    // 防止右侧超出
    if (left + tooltipWidth > width.value) {
      left = event.pageX-offsetX.value - tooltipWidth - 15;
    }

    // 防止底部超出
    if (top + tooltipHeight > window.innerHeight) {
      top = event.pageY - tooltipHeight - 10;
    }
    tooltip.value
      .style("left", `${left}px`)
      .style("top", `${top}px`)
      .html(
        `
        <div><strong>${date}</strong></div>
        ${chartData.series
          .map(
            (s) => `
            <div style="color:${s.color}">
              ${s.name}: ${s.values[index] || "N/A"}
            </div>`
          )
          .join("")}
      `
      )
      .transition()
      .duration(200)
      .style("opacity", 1);
  }

  // 重置图表样式
  function resetChartStyles() {
    // 恢复垂直网格线
    chart
      .selectAll(".grid-vertical")
      .transition()
      .duration(500)
      .attr("stroke", "#eee")
      .attr("stroke-opacity", GRID_LINE_OPACITY)
      .attr("stroke-width", 1)
      .attr("stroke-dasharray", "2,2");

    // 恢复数据点
    chartData.series.forEach((series, seriesIndex) => {
      chart
        .selectAll(`.data-point-${seriesIndex}`)
        .attr("r", 4)
        .attr("fill", series.color);
    });
  }

  // 隐藏垂直参考线
  function hideVerticalLine() {
    verticalLine.value?.transition().duration(500).attr("opacity", 0);
  }

  // 隐藏工具提示
  function hideTooltip() {
    tooltip.value?.transition().duration(500).style("opacity", 0);
  }
};
</script>

<style scoped>
.line-chart-container {
  width: 100%;
  height: 200px;
  border: none !important;
  outline: none !important;
  background: transparent;
}

.hover-area {
  pointer-events: all;
  cursor: pointer;
}

.tooltip {
  position: absolute;
  padding: 8px;
  min-width: 75px;
  background: rgba(0, 0, 0, 0.8);
  color: white;
  border-radius: 4px;
  pointer-events: none;
  font-size: 12px;
  z-index: 10;
}

.line-path {
  transition: all 0.3s ease;
}

.grid-line,
.grid-vertical {
  transition: all 0.3s ease;
}

.data-point {
  transition: all 0.3s ease;
}

.series-title text {
  transition: all 0.2s ease;
}

.series-title:hover text {
  fill: #333 !important;
}

.series-title:hover rect {
  opacity: 0.9;
}
</style>
